package com.controller;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.model.ListDataModel;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletResponse;

import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperPrintManager;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.util.JRLoader;

import org.apache.log4j.Logger;
import org.mvn_spring_jsf_jar.common.dao.BaseModelDAO;
import org.mvn_spring_jsf_jar.jasper.PagoServicioReport;
import org.mvn_spring_jsf_jar.jasper.PagoServicioTicketReport;
import org.mvn_spring_jsf_jar.model.Cliente;
import org.mvn_spring_jsf_jar.model.Configuracion;
import org.mvn_spring_jsf_jar.model.PagoServicio;
import org.mvn_spring_jsf_jar.query.BaseQuery;
import org.mvn_spring_jsf_jar.query.ClienteQuery;
import org.mvn_spring_jsf_jar.query.PagoServicioQuery;
import org.mvn_spring_jsf_jar.util.DateUtil;
import org.primefaces.event.SelectEvent;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.builder.ClienteBuilder;
import com.builder.PagoServicioBuilder;
import com.util.JSFUtil;
import com.view.ClienteSelectedView;
import com.view.PagoServicioView;

@ManagedBean
@ViewScoped
@SuppressWarnings("serial")
public class PagoServicioController extends BaseController<PagoServicio> {
	private Logger log = Logger.getLogger(PagoServicioController.class);
	private ClassPathXmlApplicationContext ctx;
	private BaseModelDAO<PagoServicio, PagoServicioQuery> dao;
	private BaseModelDAO<Cliente, ClienteQuery> clienteDAO;
	private BaseModelDAO<Configuracion, BaseQuery> configuracionDAO;
	private PagoServicioQuery pagoServicioQuery;
	private PagoServicio pagoServicio;
	private List<PagoServicio> pagoServicioList;
	private String numeroTarjeta;

	@ManagedProperty("#{pagoServicioView}")
	private PagoServicioView pagoServicioView;

	@ManagedProperty("#{clienteSelectedView}")
	private ClienteSelectedView clienteSelectedView;

	@ManagedProperty("#{pagoServicioBuilder}")
	private PagoServicioBuilder pagoServicioBuilder;

	@ManagedProperty("#{clienteBuilder}")
	private ClienteBuilder clienteBuilder;

	@SuppressWarnings("unchecked")
	public PagoServicioController() {
		ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		dao = (BaseModelDAO<PagoServicio, PagoServicioQuery>) ctx
				.getBean("pagoServicioDAO");
		clienteDAO = (BaseModelDAO<Cliente, ClienteQuery>) ctx
				.getBean("clienteDAO");
		configuracionDAO = (BaseModelDAO<Configuracion, BaseQuery>) ctx
				.getBean("configuracionDAO");
		addEdit = false;
		pagoServicioQuery = new PagoServicioQuery();
		pagoServicioQuery.setFechaDesde(new Date());
		pagoServicioQuery.setFechaHasta(new Date());
	}

	public PagoServicioView getPagoServicioView() {
		return pagoServicioView;
	}

	public void setPagoServicioView(PagoServicioView pagoServicioView) {
		this.pagoServicioView = pagoServicioView;
	}

	public PagoServicioBuilder getPagoServicioBuilder() {
		return pagoServicioBuilder;
	}

	public void setPagoServicioBuilder(PagoServicioBuilder pagoServicioBuilder) {
		this.pagoServicioBuilder = pagoServicioBuilder;
	}

	public ClienteBuilder getClienteBuilder() {
		return clienteBuilder;
	}

	public void setClienteBuilder(ClienteBuilder clienteBuilder) {
		this.clienteBuilder = clienteBuilder;
	}

	public PagoServicioQuery getPagoServicioQuery() {
		return pagoServicioQuery;
	}

	public ClienteSelectedView getClienteSelectedView() {
		return clienteSelectedView;
	}

	public void setClienteSelectedView(ClienteSelectedView clienteSelectedView) {
		this.clienteSelectedView = clienteSelectedView;
	}

	public String getNumeroTarjeta() {
		return numeroTarjeta;
	}

	public void setNumeroTarjeta(String numeroTarjeta) {
		this.numeroTarjeta = numeroTarjeta;
	}

	public void query(ActionEvent event) {
		try {
			pagoServicioQuery.setFechaHasta(DateUtil
					.getEndHourDay(pagoServicioQuery.getFechaHasta()));
			pagoServicioList = dao.getList(pagoServicioQuery);
			listDM = new ListDataModel<PagoServicio>(pagoServicioList);
		} catch (Throwable e) {
			log.error("Error al consultar: ", e);
			FacesContext.getCurrentInstance().addMessage(
					null,
					new FacesMessage(FacesMessage.SEVERITY_ERROR,
							"Error al realizar la operacion", ""));
		}
	}

	public void edit(ActionEvent event) {
		try {
			pagoServicio = (PagoServicio) listDM.getRowData();
			pagoServicioView = pagoServicioBuilder.toView(pagoServicio);
			clienteSelectedView.setCliente(pagoServicio.getCliente());
			addEdit = true;
		} catch (Throwable e) {
			log.error("Error al editar: ", e);
			FacesContext.getCurrentInstance().addMessage(
					null,
					new FacesMessage(FacesMessage.SEVERITY_ERROR,
							"Error al realizar la operacion", ""));
		}
	}

	public void delete(ActionEvent event) {
		try {
			pagoServicio = (PagoServicio) listDM.getRowData();
			dao.delete(pagoServicio);
			listDM = new ListDataModel<PagoServicio>(
					dao.getList(pagoServicioQuery));
		} catch (Throwable e) {
			log.error("Error al eliminar: ", e);
			FacesContext.getCurrentInstance().addMessage(
					null,
					new FacesMessage(FacesMessage.SEVERITY_ERROR,
							"Error al realizar la operacion", ""));
		}
	}

	public void add(ActionEvent event) {
		addEdit = true;
		clear();
	}

	public void save(ActionEvent event) {
		try {
			pagoServicioView.setClienteView(clienteBuilder
					.toView(clienteSelectedView.getCliente()));
			pagoServicio = pagoServicioBuilder.toDomain(pagoServicioView);
			if (pagoServicio.getID() != null) {
				dao.edit(pagoServicio);
				addEdit = false;
			} else {
				pagoServicio.setFecha(new Date());
				dao.save(pagoServicio);
				imprimirTicket(pagoServicio);

			}
			listDM = null;
			clear();
			JSFUtil.saveMessage("Elemento guardado con exito",
					FacesMessage.SEVERITY_INFO);
		} catch (Throwable e) {
			log.error("Error al guardar: ", e);
			FacesContext.getCurrentInstance().addMessage(
					null,
					new FacesMessage(FacesMessage.SEVERITY_ERROR,
							"Error al realizar la operacion", ""));
		}

	}

	public void cancel(ActionEvent event) {
		addEdit = false;

		Iterator<FacesMessage> msgIterator = FacesContext.getCurrentInstance()
				.getMessages();
		while (msgIterator.hasNext()) {
			msgIterator.next();
			msgIterator.remove();
		}

		clear();
	}

	public void clear() {
		listDM = null;
		pagoServicio = new PagoServicio();
		pagoServicioView = new PagoServicioView();
		clienteSelectedView.setCliente(null);
		numeroTarjeta = null;
	}

	public List<Cliente> completeCliente(String query) {
		List<Cliente> clienteList = null;
		try {
			clienteList = clienteDAO.getList(query);

		} catch (Throwable e) {
			log.error("Error en le metodo completeCliente: ", e);
			FacesContext.getCurrentInstance().addMessage(
					null,
					new FacesMessage(FacesMessage.SEVERITY_ERROR,
							"Error al realizar la operacion", ""));
		}
		return clienteList;
	}

	public void buscarPorNumeroTarjeta(ActionEvent event) {
		try {
			List<Cliente> clienteList = clienteDAO.getList(numeroTarjeta);
			if (clienteList != null && clienteList.size() == 1) {
				clienteSelectedView.setCliente(clienteList.get(0));
				pagoServicioView.setMonto(clienteList.get(0).getMontoACobrar());
			}
		} catch (Throwable e) {
			log.error("Error en el metodo buscarPorNumeroTarjeta: ", e);
			FacesContext.getCurrentInstance().addMessage(
					null,
					new FacesMessage(FacesMessage.SEVERITY_ERROR,
							"Error al realizar la operacion", ""));
		}
	}

	public boolean isClienteSelected() {
		return (clienteSelectedView.getCliente() != null);
	}

	public void deselecionarCliente(ActionEvent event) {
		clienteSelectedView.setCliente(null);
		numeroTarjeta = null;
		pagoServicioView.setMonto(null);
	}

	public void selecionarCliente(ActionEvent event) {
		clienteSelectedView.setCliente(null);
	}

	public void handleSelect(SelectEvent event) {
		numeroTarjeta = clienteSelectedView.getCliente().getNumeroTarjeta();
		pagoServicioView.setMonto(clienteSelectedView.getCliente()
				.getMontoACobrar());
	}

	@SuppressWarnings({ "rawtypes", "unchecked", "deprecation" })
	public void toPDF(ActionEvent event) {
		// InputStream reportStream;
		try {

			HttpServletResponse response = (HttpServletResponse) FacesContext
					.getCurrentInstance().getExternalContext().getResponse();
			ServletContext sc = (ServletContext) FacesContext
					.getCurrentInstance().getExternalContext().getContext();

			String realpath = sc.getRealPath(File.separator
					+ "resource/jasper/pagoServicio-reporte.jasper");

			JasperReport jasperReport = (JasperReport) JRLoader
					.loadObject(realpath);

			// Bing the datasource with the collection
			List<PagoServicioReport> list = new ArrayList<PagoServicioReport>();
			for (PagoServicio pagoServicio : pagoServicioList) {
				list.add(new PagoServicioReport(new Date(), pagoServicio
						.getID(), pagoServicio.getMonto(), pagoServicio
						.getFecha(), pagoServicio.getCliente().getNombre(),
						pagoServicio.getCliente().getNumeroTarjeta(),
						pagoServicio.getComentario()));
			}

			JRDataSource datasource = new JRBeanCollectionDataSource(list);
			// Print the jasper report
			JasperPrint print = JasperFillManager.fillReport(jasperReport,
					new HashMap(), datasource);

			response.setContentType("application/pdf");
			response.addHeader("Content-Disposition",
					"attachment; filename=ReportePagos.pdf");

			// JasperExportManager.exportReportToPdfFile(print,
			// "/home/COTESA/prodriguez/informeDePagos.pdf");

			JasperExportManager.exportReportToPdfStream(print,
					response.getOutputStream());

			FacesContext.getCurrentInstance().responseComplete();
		} catch (Throwable e) {
			log.error("Error al exportar a PDF: ", e);
			FacesContext.getCurrentInstance().addMessage(
					null,
					new FacesMessage(FacesMessage.SEVERITY_ERROR,
							"Error al exportar a PDF", ""));
			System.out.println("error al exportar: " + e.getMessage());
		}
	}

	@SuppressWarnings({ "unchecked", "deprecation", "rawtypes" })
	private void imprimirTicket(PagoServicio pagoServicio) {
		try {

			ServletContext sc = (ServletContext) FacesContext
					.getCurrentInstance().getExternalContext().getContext();

			String realpath = sc.getRealPath(File.separator
					+ "resource/jasper/pagoServicioTicket.jasper");

			JasperReport jasperReport = (JasperReport) JRLoader
					.loadObject(realpath);

			// Bing the datasource with the collection
			List<PagoServicioTicketReport> list = new ArrayList<PagoServicioTicketReport>();
			Configuracion configuracion = configuracionDAO.getList().get(0);

			Random r = new Random();
			r.setSeed(129856l);
			Long numeroControl = r.nextLong();

			list.add(new PagoServicioTicketReport(configuracion
					.getNombreEmpresa(), pagoServicio.getCliente().getNombre(),
					pagoServicio.getMonto(), pagoServicio.getFecha(),
					pagoServicio.getID(), pagoServicio.getCliente()
							.getNumeroTarjeta(), Math.abs(numeroControl
							.longValue()), configuracion.getLeyendaTicket()));

			JRDataSource datasource = new JRBeanCollectionDataSource(list);
			// Print the jasper report
			JasperPrint print = JasperFillManager.fillReport(jasperReport,
					new HashMap(), datasource);

			JasperPrintManager.printReport(print, false);
		} catch (Throwable e) {
			log.error("Error al imprimir el ticket: ", e);
			FacesContext.getCurrentInstance().addMessage(
					null,
					new FacesMessage(FacesMessage.SEVERITY_ERROR,
							"Error al imprimir el ticket", ""));
		}
	}
}
